import { clone, isArray, isPlainObject, toTreeArray } from "xe-utils";
import store from "@/store/index";
import Layout from "@/layout";
import EmptyLayout from "@/layout/empty";
function hasPermission(permission) {
  if (store.state.settings.openPermission) {
    return store.state.user.permissions.some((v) => {
      return v === permission;
    });
  } else {
    return true;
  }
}

export function auth(value) {
  let auth;
  if (typeof value === "string") {
    auth = hasPermission(value);
  } else if (isArray(value)) {
    auth = value.some((item) => {
      return hasPermission(item);
    });
  }
  return auth;
}

export function authAll(value) {
  const auth = value.every((item) => {
    return hasPermission(item);
  });
  return auth;
}

export function swapArray(arr, index1, index2) {
  arr[index1] = arr.splice(index2, 1, arr[index1])[0];
  return arr;
}

export function filterParams(data) {
  if (isPlainObject(data)) {
    for (const key in data) {
      if (isPlainObject(data[key])) {
        data[key] = filterParams(data[key]);
      } else if (isArray(data[key])) {
        data[key] = data[key].map((item) => {
          return filterParams(item);
        });
      } else {
        if (
          Object.prototype.hasOwnProperty.call(data, key) &&
          (data[key] === null ||
            data[key] === "null" ||
            data[key] === undefined ||
            data[key] === "undefined" ||
            key.startsWith("__"))
        ) {
          delete data[key];
        }
      }
    }
  }
  return data;
}

export function generateKVMap(data) {
  return data.reduce(
    (map, { code, key, value }) => ({
      ...map,
      [code]: {
        ...map[code],
        [key]: value,
      },
    }),
    {},
  );
}

export function generateOptionsMap(data) {
  return data.reduce(
    (map, { code, key, value }) => ({
      ...map,
      [code]: [...(map[code] || []), { label: value, value: key }],
    }),
    {},
  );
}

export function generateFormOptionsMap(data) {
  const optionsMap = generateOptionsMap(data);
  return Object.keys(optionsMap).reduce((map, key) => {
    const option = clone(optionsMap[key]);
    option.unshift({ label: "全部", value: "" });
    map[key] = option;
    return map;
  }, {});
}

export function convertToTree(flatData, parentId = null, name = "parentId") {
  const children = flatData.filter((node) => node[name] === parentId);
  if (!children.length) {
    return null;
  }
  return children.map((node) => ({
    ...node,
    children: convertToTree(flatData, node.id, name),
  }));
}

export function getChildrenByParentId(data, parentId) {
  const arr = [];
  data.forEach((item) => {
    if (item.parentId === parentId) {
      arr.push(item);
      arr.push(...getChildrenByParentId(data, item.id));
    }
  });
  return arr;
}
function getUrlParent(url) {
  const urlArr = url.split("/");
  urlArr.pop();
  return urlArr.join("/");
}

function sortBy(field) {
  //根据传过来的字段进行排序
  return (x, y) => {
    return x[field] - y[field];
  };
}
export function addTree(data) {
  let newData = [...data];
  const isHightData = clone(data);
  data.forEach((item) => {
    try {
      if (!item.parentId && hasOne(data, item.id)) {
        let obj = {};
        const numbers = Math.random().toFixed(8);
        obj = {
          ...item,
          parentId: null,
          id: numbers,
          redirectUrl: item.redirectUrl,
          isBreadcrumbShow: true,
          isNavbarShow: true,
          parameters: "#",
          // url: getUrlParent(item.url),
          url: item.url,
        };
        item.parentId = numbers;
        item.redirectUrl = "";
        item.isBreadcrumbShow = false;
        item.isNavbarShow = false;
        item.code = `${item.code}_partent`;
        // item.highlightUrl = getUrlParent(item.url);
        item.highlightUrl = item.url;
        newData.push(obj);
      }
    } catch (e) {
      console.log(e);
    }
  });
  newData = newData.sort(sortBy("orderValue"));
  //为不显示菜单的子选项增加高亮
  newData.forEach((item1) => {
    if (!item1.isNavbarShow && !item1.highlightUrl) {
      isHightData.forEach((item2) => {
        if (item1.parentId == item2.id) {
          item1.highlightUrl = item2.url;
        }
      });
    }
    //增加路由全地址
    isHightData.forEach((item2) => {
      if (item1.parentId == item2.id) {
        if (item1.url.charAt(0) == "/") {
          item1.fullPath = item2.url + item1.url;
        } else {
          item1.fullPath = `${item2.url}/${item1.url}`;
        }
      }
    });
  });
  // console.log(newData);
  return newData;
}

export function hasOne(data, id) {
  let nums = 0;
  const dataParams = clone(data);
  dataParams.forEach((item) => {
    if (item.parentId == id) {
      nums++;
    }
  });
  return nums == 0; //true代表仅有一个  false代表有多个
}
export function toMenus(routes, data, route) {
  if (data?.length) {
    data.forEach((item) => {
      // const activeMenu = item.highlightUrl
      //   ? {
      //       activeMenu: item.highlightUrl,
      //     }
      //   : {};
      let component;
      let activeMenu;
      if (item.parameters === "#") {
        component = Layout;
      } else if (item.parameters === "##") {
        component = EmptyLayout;
      } else {
        component = (resolve) => require([`@/views${item.parameters}.vue`], resolve);
      }
      if (!item.isNavbarShow && route) {
        activeMenu = route.fullPath;
        // activeMenu=
      }
      try {
        const menu = {
          path: item.url,
          component,
          redirect: item.redirectUrl,
          name: item.code,
          fullPath: item.fullPath,
          meta: {
            title: item.name,
            icon: item.icon,
            activeIcon: item.icon?.indexOf("el") != "-1" ? item.icon : item.icon ? `${item.icon}-active` : "",
            sidebar: item.isNavbarShow,
            keepAlive: item.isBreadcrumbShow,
            // ...activeMenu,
            activeMenu,
          },
        };
        if (item.children) {
          menu.children = [];
          toMenus(menu.children, item.children, menu);
        }
        routes.push(menu);
      } catch (err) {
        console.log(err);
      }
    });
    return routes;
  } else {
    return [];
  }
}
/**
 * 将科学计数法的数字转为字符串
 * 说明：运算精度丢失方法中处理数字的时候，如果出现科学计数法，就会导致结果出错
 * 4.496794759834739e-9  ==> 0.000000004496794759834739
 * 4.496794759834739e+9  ==> 4496794759.834739
 * @param  num
 */
export function toNonExponential(num) {
  if (num == null) {
    return num;
  }
  if (typeof num == "number") {
    const m = num.toExponential().match(/\d(?:\.(\d*))?e([+-]\d+)/);
    return num.toFixed(Math.max(0, (m[1] || "").length - m[2]));
  } else {
    return num;
  }
}

/**
 * 乘法 - js运算精度丢失问题
 * @param arg1  数1
 * @param arg2  数2
 * 0.0023 * 100 ==> 0.22999999999999998
 * {{ 0.0023 | multiply(100) }} ==> 0.23
 */
export function floatMultiply(arg1, arg2) {
  arg1 = Number(arg1);
  arg2 = Number(arg2);
  if ((!arg1 && arg1 !== 0) || (!arg2 && arg2 !== 0)) {
    return null;
  }
  arg1 = toNonExponential(arg1);
  arg2 = toNonExponential(arg2);
  let r1;
  let r2; // 小数位数
  try {
    r1 = arg1.toString().split(".")[1].length;
  } catch (e) {
    r1 = 0;
  }
  try {
    r2 = arg2.toString().split(".")[1].length;
  } catch (e) {
    r2 = 0;
  }
  const n1 = Number(arg1.toString().replace(".", ""));
  const n2 = Number(arg2.toString().replace(".", ""));
  return (n1 * n2) / Math.pow(10, r1 + r2);
}

/**
 * 除法 - js运算精度丢失问题
 * @param arg1  数1
 * @param arg2  数2
 * 0.0023 / 0.00001 ==> 229.99999999999997
 * {{ 0.0023 | divide(0.00001) }} ==> 230
 */
export function floatDivide(arg1, arg2) {
  arg1 = Number(arg1);
  arg2 = Number(arg2);
  if (!arg2) {
    return null;
  }
  if (!arg1 && arg1 !== 0) {
    return null;
  } else if (arg1 === 0) {
    return 0;
  }
  arg1 = toNonExponential(arg1);
  arg2 = toNonExponential(arg2);
  let r1;
  let r2; // 小数位数
  try {
    r1 = arg1.toString().split(".")[1].length;
  } catch (e) {
    r1 = 0;
  }
  try {
    r2 = arg2.toString().split(".")[1].length;
  } catch (e) {
    r2 = 0;
  }
  const n1 = Number(arg1.toString().replace(".", ""));
  const n2 = Number(arg2.toString().replace(".", ""));
  return floatMultiply(n1 / n2, Math.pow(10, r2 - r1));
  // return (n1 / n2) * Math.pow(10, r2 - r1);   // 直接乘法还是会出现精度问题
}

/**
 * 加法 - js运算精度丢失问题
 * @param arg1  数1
 * @param arg2  数2
 * 0.0023 + 0.00000000000001 ==> 0.0023000000000099998
 * {{ 0.0023 | plus(0.00000000000001) }} ==> 0.00230000000001
 */
export function floatAdd(arg1, arg2) {
  arg1 = Number(arg1) || 0;
  arg2 = Number(arg2) || 0;
  arg1 = toNonExponential(arg1);
  arg2 = toNonExponential(arg2);
  let r1;
  let r2;
  try {
    r1 = arg1.toString().split(".")[1].length;
  } catch (e) {
    r1 = 0;
  }
  try {
    r2 = arg2.toString().split(".")[1].length;
  } catch (e) {
    r2 = 0;
  }
  const m = Math.pow(10, Math.max(r1, r2));
  return (floatMultiply(arg1, m) + floatMultiply(arg2, m)) / m;
}

/**
 * 减法 - js运算精度丢失问题
 * @param arg1  数1
 * @param arg2  数2
 * 0.0023 - 0.00000011  ==>  0.0022998899999999997
 * {{ 0.0023 | minus( 0.00000011 ) }}  ==>  0.00229989
 */
export function floatSub(arg1, arg2) {
  arg1 = Number(arg1) || 0;
  arg2 = Number(arg2) || 0;
  arg1 = toNonExponential(arg1);
  arg2 = toNonExponential(arg2);
  let r1;
  let r2;
  try {
    r1 = arg1.toString().split(".")[1].length;
  } catch (e) {
    r1 = 0;
  }
  try {
    r2 = arg2.toString().split(".")[1].length;
  } catch (e) {
    r2 = 0;
  }
  const m = Math.pow(10, Math.max(r1, r2));
  // 动态控制精度长度
  const n = r1 >= r2 ? r1 : r2;
  return ((floatMultiply(arg1, m) - floatMultiply(arg2, m)) / m).toFixed(n);
}

/**
 * 取余 - js运算精度丢失问题
 * @param arg1  数1
 * @param arg2  数2
 * 12.24 % 12  ==> 0.2400000000000002
 * {{ 12.24 | mod( -12 ) }}  ==>  0.24
 */
export function floatMod(arg1, arg2) {
  arg1 = Number(arg1);
  arg2 = Number(arg2);
  if (!arg2) {
    return null;
  }
  if (!arg1 && arg1 !== 0) {
    return null;
  } else if (arg1 === 0) {
    return 0;
  }
  let intNum = arg1 / arg2;
  intNum = intNum < 0 ? Math.ceil(arg1 / arg2) : Math.floor(arg1 / arg2); // -1.02 取整为 -1; 1.02取整为1
  const intVal = floatMultiply(intNum, arg2);
  return floatSub(arg1, intVal);
}
export function unique(arr1, name) {
  const res = new Map();
  return arr1.filter((item) => !res.has(item[name]) && res.set(item[name], 1));
}
export function arrayAminusB(arrA, arrB) {
  return arrA.filter((v) => !arrB.includes(v));
}
export function haveRole(data, url) {
  let have = false;
  const roleList = toTreeArray(data);
  roleList.some((item) => {
    if (item.fullPath && item.fullPath.indexOf(url) != -1) {
      have = true;
      return false;
    }
  });
  return have;
}
//交互数组位置
export function swapArr(arr, index1, index2) {
  arr[index1] = arr.splice(index2, 1, arr[index1])[0];
  return arr;
}
//限制输入正数，保留limit位小数
export function decimal(num, limit = 1000000) {
  let str = num;
  const len1 = str.substr(0, 1);
  const len2 = str.substr(1, 1);
  //如果第一位是0，第二位不是点，就用数字把点替换掉
  if (str.length > 1 && len1 == 0 && len2 != ".") {
    str = str.substr(1, 1);
  }
  //第一位不能是.
  if (len1 == ".") {
    str = "";
  }
  //限制只能输入一个小数点
  if (str.indexOf(".") != -1) {
    const str_ = str.substr(str.indexOf(".") + 1);
    if (str_.indexOf(".") != -1) {
      str = str.substr(0, str.indexOf(".") + str_.indexOf(".") + 1);
    }
  }
  const reg = new RegExp(`^\\D*([0-9]\\d*\\.?\\d{0,${limit}})?.*$`);
  //正则替换
  str = str.replace(/[^\d^.]+/g, ""); // 保留数字和小数点
  str = str.replace(reg, "$1"); // 小数点后只能输 limit 位
  return str;
}
export function getLastPath(value, path = "", level = 0) {
  if (value[0].children) {
    const newLevel = ++level;
    let newPath = "";
    if (newLevel > 1) {
      newPath = path + value[0].path;
    } else {
      newPath = "";
    }
    return getLastPath(value[0].children, newPath, newLevel);
  } else {
    if (level > 1) {
      return `${path}/${value[0].path}`;
    } else {
      return value[0].path;
    }
  }
}

// limit小数位数，limitIn整数位数
export const numberLimit = (num, limit = 2, limitIn = 11) => {
  let str = num;
  const len1 = str.substr(0, 1);
  const len2 = str.substr(1, 1);
  //如果第一位是0，第二位不是点，就用数字把点替换掉
  if (str.length > 1 && len1 == 0 && len2 != ".") {
    str = str.substr(1, 1);
  }
  //第一位不能是.
  if (len1 == ".") {
    str = "";
  }
  //限制只能输入一个小数点
  if (str.indexOf(".") != -1) {
    const str_ = str.substr(str.indexOf(".") + 1);
    if (str_.indexOf(".") != -1) {
      str = str.substr(0, str.indexOf(".") + str_.indexOf(".") + 1);
    } else {
      //暂时处理小数点位数多余11位
      const list_str = str.split(".");
      const zs = list_str[0];
      const xs = list_str[1];
      const zsReg = new RegExp(`^(\\d{${limitIn}})\\d$`, "g");
      const zsNew = zs.replace(zsReg, "$1");
      const xsReg = new RegExp(`^(\\d{${limit}})\\d$`, "g");
      const xsNew = xs.replace(xsReg, "$1");
      str = `${zsNew}.${xsNew}`;
      // if (!xsNew) {
      //   str = xsNew.length > 0 ? `${zsNew}.${xsNew}` : `${zsNew}`;
      // }
    }
  }
  const reg = new RegExp(`^\\D*([0-9]\\d*\\.?\\d{0,${limit}})?.*$`);
  //正则替换
  str = str.replace(/[^\d^\\.]+/g, ""); // 保留数字和小数点
  str = str.replace(reg, "$1"); // 小数点后只能输 limit 位
  const regIn = new RegExp(`^(\\d{${limitIn}})\\d$`, "g");
  str = str.replace(regIn, "$1");
  return str;
};
